﻿using IPlugin;
using IPlugin.Attributes;
using Mohe.Scada.Util.Models;
using NLog;
using Opc.Ua;

namespace OpcUa.Client
{
    [DriverInfo("OpcUa", "1.0.0", "湖州精确科技有限公司")]
    public class OpcUaDriver : IDriver
    {
        private static Logger _logger = LogManager.GetLogger(nameof(OpcUaClient));

        private OpcUaClient opcUaClient;
        private readonly string _device;
        #region 配置参数
        [ConfigParameter("设备ID")]
        public int DeviceId { get; set; }
        [ConfigParameter("Uri")]
        public string Uri { get; set; } = "opc.tcp://localhost:53530/OPCUA/SimulationServer";

        [ConfigParameter("超时时间ms")]
        public int TimeOut { get; set; } = 3000;
        [ConfigParameter("最小通讯周期ms")]
        public int MinPeriod { get; set; } = 3000;
        [ConfigParameter("订阅主题")]
        public string SubTopic { get; set; } = string.Empty;
        [ConfigParameter("用户")]
        public string UserName { get; set; } = string.Empty;
        [ConfigParameter("密码")]
        public string Password { get; set; } = string.Empty;
        #endregion



        public OpcUaDriver(string device)
        {
            _device = device;

            _logger.Info($"OpcUaDriver Create. Device{_device}");
        }

        public bool Close()
        {
            try
            {
                opcUaClient?.Disconnect();
                return !IsConnected;
            }
            catch (Exception ex)
            {
                _logger.Error(ex);
                return false;
            }
        }

        public bool Connect()
        {
            try
            {
                opcUaClient = new OpcUaClient();
                opcUaClient.UserIdentity = new UserIdentity(new AnonymousIdentityToken());
                if (!string.IsNullOrEmpty(UserName))
                {
                    opcUaClient.UserIdentity = new UserIdentity(UserName, Password);
                    opcUaClient.UseSecurity = true;

                }
                opcUaClient.ConnectServer(Uri).Wait(TimeOut);


            }
            catch (Exception ex)
            {
                _logger.Error(ex, $"连接失败 Device:{_device}");
                return false;
            }
            return IsConnected;
        }



        public void Dispose()
        {
            try
            {
                _logger.Info("OpcUaDriver Dispose.");
                opcUaClient = null;
                GC.SuppressFinalize(this);
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "释放失败");
            }
        }
        [Method("读OPCUa", description: "读OPCUa节点")]
        public DriverReturnValueModel Read(DriverAddressIoArgModel ioArg)
        {
            var ret = new DriverReturnValueModel { StatusType = EnumVariableStatus.Good };

            if (IsConnected)
            {
                try
                {
                    var dataValue = opcUaClient?.ReadNode(new NodeId(ioArg.Address));
                    if (DataValue.IsGood(dataValue))
                        ret.Value = dataValue?.Value;
                }
                catch (Exception ex)
                {
                    ret.StatusType = EnumVariableStatus.Bad;
                    ret.Message = $"读取失败,{ex.Message}";
                    _logger.Error(ex, $"读取失败{ioArg.Address}");
                }
            }
            else
            {
                ret.StatusType = EnumVariableStatus.Bad;
                ret.Message = "连接失败";
            }

            return ret;
        }
        [Method("写OPCUa", description: "写OPCUa节点")]
        public async Task<RpcResponse> WriteAsync(string RequestId, string Method, DriverAddressIoArgModel ioArg)
        {
            RpcResponse ret = new RpcResponse() { IsSuccess = false };
            if (IsConnected)
            {
                try
                {
                    ret.IsSuccess = await opcUaClient.WriteNodeAsync(ioArg.Address, ioArg.Value);
                }
                catch (Exception ex)
                {
                    ret.Description = $"写入失败,{ex.Message}";
                }
            }
            else
            {
                ret.Description = "连接失败";
            }
            return ret;
        }

        public bool IsConnected
        {
            get
            {
                if (opcUaClient == null)
                {
                    return false;
                }
                return opcUaClient.Connected;


            }
            set => IsConnected = value;
        }


    }
}
